home *** CD-ROM | disk | FTP | other *** search
- {:Monitoring components for some file system-based synchronisation primitives.
- (c) 2001 Primoz Gabrijelcic
-
- @author Primoz Gabrijelcic
- @desc <pre>
-
- Free for personal and commercial use.
- Tested with Delphi 5. Should work with Delphi 4 but not with older versions.
-
- Author : Primoz Gabrijelcic
- Creation date : 2001-01-06
- Last modification: 2001-02-27
- Version : 1.0
-
- </pre>}{
-
- History:
- 1.0: 2001-02-27
- - First release version.
-
- 0.1: 2001-01-06
- - First alpha version.
- }
-
- unit GpFileSyncMonitors;
-
- interface
-
- uses
- Windows,
- Messages,
- Classes,
- GpFileSync;
-
- const
- CShortDelay = 250; // ms
- CInterval = 5000; // ms
-
- type
- {:Monitors a mutex and reports all changes.
- }
- TGpFileMutexMonitor = class(TComponent)
- private
- FAcquired : boolean;
- FActive : boolean;
- FDeleteOnRelease: boolean;
- FFileMutex : TGpFileMutex;
- FHandle : HWND;
- FInterval : integer;
- FMonitorThread : TThread;
- FMutexFile : string;
- FOnAcquired : TNotifyEvent;
- FOnReleased : TNotifyEvent;
- FShortDelay : integer;
- FStreamedActive : boolean;
- protected
- procedure DoAcquired; virtual;
- procedure DoReleased; virtual;
- procedure Loaded; override;
- procedure SetActive(const Value: boolean); virtual;
- procedure StartMonitorThread(reportFirst: boolean); virtual;
- procedure StopMonitorThread; virtual;
- procedure WndProc(var MsgRec: TMessage); virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function Acquire(timeout: DWORD): boolean; virtual;
- function Acquired: boolean; virtual;
- function IsFree(timeout: DWORD): boolean;
- procedure Release; virtual;
- published
- //:Specifies if monitoring is active.
- property Active: boolean read FActive write SetActive;
- //:Timeout (in ms) used when checking if mutex is acquired. Passed to TGpFileMutex.Acquired.
- property CheckTimeout: integer read FShortDelay write FShortDelay default CShortDelay;
- //:Specifies if synchronisation file should be deleted on release. Passed to TGpFileMutex.Create.
- property DeleteOnRelease: boolean read FDeleteOnRelease write FDeleteOnRelease;
- //:Interval (in ms) between two checks.
- property Interval: integer read FInterval write FInterval default CInterval;
- //:True if mutex is acquired by some other owner (not by self).
- property IsAcquired: boolean read FAcquired;
- //:Mutex synchronisation file.
- property MutexFile: string read FMutexFile write FMutexFile;
- {:Triggered when mutex is acquired. Due to the design choices this event
- doesn't trigger when mutex is acquired from within this component
- (self.Acquire). For the same reason this event may in some conditions be
- triggered even if previous mutex status was Acquired, too.
- }
- property OnAcquired: TNotifyEvent read FOnAcquired write FOnAcquired;
- {:Triggered when mutex is released. Due to the design choices this event
- doesn't trigger when mutex is released from within this component
- (self.Release). For the same reason this event may in some conditions be
- triggered even if previous mutex status was Released, too.
- }
- property OnReleased: TNotifyEvent read FOnReleased write FOnReleased;
- end; { TGpFileMutexMonitor }
-
- {:Monitors a group and reports all changes.
- }
- TGpFileGroupMonitor = class(TComponent)
- private
- FActive : boolean;
- FDeleteOnRelease: boolean;
- FEmpty : boolean;
- FFileGroup : TGpFileGroup;
- FGroupFile : string;
- FHandle : HWND;
- FInterval : integer;
- FMonitorThread : TThread;
- FOnEmpty : TNotifyEvent;
- FOnNotEmpty : TNotifyEvent;
- FShortDelay : integer;
- FStreamedActive : boolean;
- protected
- procedure DoEmpty; virtual;
- procedure DoNotEmpty; virtual;
- procedure Loaded; override;
- procedure SetActive(const Value: boolean); virtual;
- procedure StartMonitorThread(reportFirst: boolean); virtual;
- procedure StopMonitorThread; virtual;
- procedure WndProc(var MsgRec: TMessage); virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function IsMember: boolean;
- function Join(timeout: DWORD; var isFirstMember: boolean): boolean; overload;
- function Join(timeout: DWORD): boolean; overload;
- function Leave(timeout: DWORD; var wasLastMember: boolean): boolean; overload;
- function Leave(timeout: DWORD): boolean; overload;
- published
- //:Specifies if monitoring is active.
- property Active: boolean read FActive write SetActive;
- //:Timeout (in ms) used when checking if group is empty. Passed to TGpFileGroup.Join.
- property CheckTimeout: integer read FShortDelay write FShortDelay default CShortDelay;
- //:Specifies if synchronisation file should be deleted on release. Passed to TGpFileGroup.Create.
- property DeleteOnRelease: boolean read FDeleteOnRelease write FDeleteOnRelease;
- //:Interval (in ms) between two checks.
- property Interval: integer read FInterval write FInterval default CInterval;
- //:True if group is empty.
- property IsEmpty: boolean read FEmpty;
- //:Group synchronisation file.
- property GroupFile: string read FGroupFile write FGroupFile;
- {:Triggered when group becomes empty. Due to the design choices this event
- may in some conditions be triggered even if previous group status was
- Empty, too.
- }
- property OnEmpty: TNotifyEvent read FOnEmpty write FOnEmpty;
- {:Triggered when group becomes nonempty. Due to the design choices this
- event may in some conditions be triggered even if previous group status
- was NotEmpty, too.
- }
- property OnNotEmpty: TNotifyEvent read FOnNotEmpty write FOnNotEmpty;
- end; { TGpFileMutexMonitor }
-
- procedure Register;
-
- implementation
-
- uses
- SysUtils,
- Forms;
-
- const
- WM_ACQUIRED = WM_USER;
- WM_RELEASED = WM_USER+1;
- WM_EMPTY = WM_USER+2;
- WM_NOTEMPTY = WM_USER+3;
-
- type
- {:Base monitor thread class - implements TerminateEvent support.
- }
- TGpFileAnyMonitorThread = class(TThread)
- public
- TerminateEvent: THandle;
- constructor Create(CreateSuspended: boolean);
- destructor Destroy; override;
- procedure Execute; override;
- procedure SafeExecute; virtual; abstract;
- procedure Terminate;
- property Terminated;
- end; { TGpFileAnyMonitorThread }
-
- {:File mutex monitor - monitors mutex and notifies owner of changes.
- }
- TGpFileMutexMonitorThread = class(TGpFileAnyMonitorThread)
- private
- FCheckInterval: integer;
- FFileMutex : TGpFileMutex;
- FParentWin : HWND;
- FShortDelay : integer;
- FReportFirst : boolean;
- procedure TriggerStatusChange(isFree: boolean);
- public
- constructor Create(parentWin: HWND; checkInterval: integer;
- mutexFile: string; deleteOnRelease: boolean; shortDelay: integer;
- reportFirst: boolean);
- destructor Destroy; override;
- procedure SafeExecute; override;
- end; { TGpFileMutexMonitorThread }
-
- {:File group monitor - monitors group and notifies owner of changes.
- }
- TGpFileGroupMonitorThread = class(TGpFileAnyMonitorThread)
- private
- FCheckInterval: integer;
- FFileGroup : TGpFileGroup;
- FParentWin : HWND;
- FShortDelay : integer;
- FReportFirst : boolean;
- procedure TriggerStatusChange(isEmpty: boolean);
- public
- constructor Create(parentWin: HWND; checkInterval: integer;
- groupFile: string; deleteOnRelease: boolean; shortDelay: integer;
- reportFirst: boolean);
- destructor Destroy; override;
- procedure SafeExecute; override;
- end; { TGpFileMutexMonitorThread }
-
- resourcestring
- SAlreadyJoined = 'Already joined: %s.';
- SNotJoined = 'Not member: %s.';
-
- procedure Register;
- begin
- RegisterComponents('Gp',[TGpFileMutexMonitor,TGpFileGroupMonitor]);
- end; { Register }
-
- { TGpFileAnyMonitorThread }
-
- {:Base monitor thread class constructor.
- }
- constructor TGpFileAnyMonitorThread.Create(CreateSuspended: boolean);
- begin
- TerminateEvent := CreateEvent(nil, true, false, nil);
- inherited Create(CreateSuspended);
- end; { TGpFileAnyMonitorThread.Create }
-
- {:Base monitor thread class destructor.
- }
- destructor TGpFileAnyMonitorThread.Destroy;
- begin
- CloseHandle(TerminateEvent);
- inherited;
- end; { TGpFileAnyMonitorThread.Destroy }
-
- {:Base monitor thread class Execute method. Calls abstract SafeExecute method
- and makes sure that Terminate is called at the end to set TerminateEvent.
- }
- procedure TGpFileAnyMonitorThread.Execute;
- begin
- try
- SafeExecute;
- finally
- Terminate; // set Terminated
- end;
- end; { TGpFileAnyMonitorThread.Execute }
-
- {:Statically overridden (sadly, Terminate is not virtual in TThread) to set
- TerminateEvent.
- }
- procedure TGpFileAnyMonitorThread.Terminate;
- begin
- inherited;
- SetEvent(TerminateEvent);
- end; { TGpFileAnyMonitorThread.Terminate }
-
- { TGpFileMutexMonitorThread }
-
- {:Mutex monitor thread constructor.
- }
- constructor TGpFileMutexMonitorThread.Create(parentWin: HWND;
- checkInterval: integer; mutexFile: string; deleteOnRelease: boolean;
- shortDelay: integer; reportFirst: boolean);
- begin
- FParentWin := parentWin;
- FCheckInterval := checkInterval;
- FShortDelay := shortDelay;
- FReportFirst := reportFirst;
- FFileMutex := TGpFileMutex.Create(mutexFile,deleteOnRelease);
- inherited Create(false);
- end; { TGpFileMutexMonitorThread.Create }
-
- {:Mutex monitor thread destructor.
- }
- destructor TGpFileMutexMonitorThread.Destroy;
- begin
- //safety precaution - that way code will work correctly if caller forgets to Terminate this thread
- Terminate;
- WaitFor;
- //>
- FreeAndNil(FFileMutex);
- inherited;
- end; { TGpFileMutexMonitorThread.Destroy }
-
- {:Mutex monitor thread main execute loop. Monitors for mutex changes and reports
- them to the owner.
- }
- procedure TGpFileMutexMonitorThread.SafeExecute;
- var
- newIsFree: boolean;
- oldIsFree: boolean;
- begin
- oldIsFree := FFileMutex.IsFree(FShortDelay);
- if FReportFirst or (not oldIsFree) then
- TriggerStatusChange(oldIsFree);
- while WaitForSingleObject(TerminateEvent,FCheckInterval) = WAIT_TIMEOUT do begin
- newIsFree := FFileMutex.IsFree(FShortDelay);
- if newIsFree <> oldIsFree then begin
- TriggerStatusChange(newIsFree);
- oldIsFree := newIsFree;
- end;
- end; //while
- end; { TGpFileMutexMonitorThread.SafeExecute }
-
- {:Report mutex status change to the owner by posting an user message.
- }
- procedure TGpFileMutexMonitorThread.TriggerStatusChange(isFree: boolean);
- begin
- if isFree then
- PostMessage(FParentWin,WM_RELEASED,0,0)
- else
- PostMessage(FParentWin,WM_ACQUIRED,0,0);
- end; { TGpFileMutexMonitorThread.TriggerStatusChange }
-
- { TGpFileMutexMonitor }
-
- {:Tries to acquire mutex.
- @param timeout Timeout in milliseconds. 0 and INFINITE are supported.
- @returns true if mutex was acquired.
- @raises EGpFileSync if sync file cannot be created of if mutex is already
- acquired.
- }
- function TGpFileMutexMonitor.Acquire(timeout: DWORD): boolean;
- begin
- if assigned(FFileMutex) then
- Result := false
- else begin
- StopMonitorThread;
- FFileMutex := TGpFileMutex.Create(FMutexFile,FDeleteOnRelease);
- Result := FFileMutex.Acquire(timeout);
- if not Result then
- Release
- else if FAcquired then // monitoring thread failed to notice that mutex is no longer acquired
- DoReleased;
- end;
- end; { TGpFileMutexMonitor.Acquire }
-
- {:Checks if mutex is acquired.
- returns true if mutex is currently acquired by self.
- }
- function TGpFileMutexMonitor.Acquired: boolean;
- begin
- Result := assigned(FFileMutex);
- end; { TGpFileMutexMonitor.Acquired }
-
- {:Creates mutex monitor component.
- @param AOwner Component owner.
- }
- constructor TGpFileMutexMonitor.Create(AOwner: TComponent);
- begin
- inherited;
- FInterval := 5000;
- FShortDelay := CShortDelay;
- FHandle := AllocateHWnd(WndProc);
- end; { TGpFileMutexMonitor.Create }
-
- {:Destroys mutex monitor component.
- }
- destructor TGpFileMutexMonitor.Destroy;
- begin
- StopMonitorThread;
- DeallocateHWnd(FHandle);
- FreeAndNil(FFileMutex);
- inherited;
- end; { TGpFileMutexMonitor.Destroy }
-
- {:Called when mutex is acquired (by another owner). Sets internal flag and
- triggers OnAcquired event.
- }
- procedure TGpFileMutexMonitor.DoAcquired;
- begin
- FAcquired := true;
- if assigned(FOnAcquired) then
- FOnAcquired(self);
- end; { TGpFileMutexMonitor.DoAcquired }
-
- {:Called when mutex is released (by another owner). Sets internal flag and
- triggers OnAcquired event.
- }
- procedure TGpFileMutexMonitor.DoReleased;
- begin
- FAcquired := false;
- if assigned(FOnReleased) then
- FOnReleased(self);
- end; { TGpFileMutexMonitor.DoReleased }
-
- {:Checks if mutex can be acquired but does not acquire it.
- @returns true if mutex can be acquired.
- @raises EGpFileSync if sync file cannot be created.
- }
- function TGpFileMutexMonitor.IsFree(timeout: DWORD): boolean;
- begin
- if Acquire(timeout) then begin
- Release;
- Result := true;
- end
- else
- Result := false;
- end; { TGpFileMutexMonitor.IsFree }
-
- {:Called when component is fully loaded. Sets delay-loaded Active property.
- }
- procedure TGpFileMutexMonitor.Loaded;
- begin
- inherited;
- if FStreamedActive then
- Active := true;
- end; { TGpFileMutexMonitor.Loaded }
-
- {:Releases mutex. Does nothing if mutex is not acquired.
- }
- procedure TGpFileMutexMonitor.Release;
- begin
- FreeAndNil(FFileMutex);
- if FActive then
- StartMonitorThread(false);
- end; { TGpFileMutexMonitor.Release }
-
- {:Sets Active property. If called during component loading, stores new value to
- be set later when component is fully loaded. Otherwise, starts or stops
- monitoring thread if required.
- @param Value New value of Active property.
- }
- procedure TGpFileMutexMonitor.SetActive(const Value: boolean);
- begin
- if (csReading in ComponentState) then
- FStreamedActive := Value
- else begin
- if FActive <> Value then begin
- FActive := Value;
- // if FFileMutex is assigned, thread is already stopped and should not be
- // restarted - it will be restarted in .Release
- if not assigned(FFileMutex) then begin
- if FActive then
- StartMonitorThread(true)
- else
- StopMonitorThread;
- end;
- end;
- end;
- end; { TGpFileMutexMonitor.SetActive }
-
- {:Starts monitor thread (if not already started).
- }
- procedure TGpFileMutexMonitor.StartMonitorThread(reportFirst: boolean);
- begin
- if not assigned(FMonitorThread) then begin
- FMonitorThread := TGpFileMutexMonitorThread.Create(FHandle,FInterval,
- FMutexFile,FDeleteOnRelease,FShortDelay,reportFirst);
- end;
- end; { TGpFileMutexMonitor.StartMonitorThread }
-
- {:Stops monitor thread (if not already stopped).
- }
- procedure TGpFileMutexMonitor.StopMonitorThread;
- begin
- if assigned(FMonitorThread) then begin
- TGpFileMutexMonitorThread(FMonitorThread).Terminate;
- FMonitorThread.WaitFor;
- FreeAndNil(FMonitorThread);
- end;
- end; { TGpFileMutexMonitor.StopMonitorThread }
-
- {:Windows message handler. Catches WM_ACQUIRED and WM_RELEASED user messages and
- converts them into events.
- }
- procedure TGpFileMutexMonitor.WndProc(var MsgRec: TMessage);
- begin
- with MsgRec do begin
- if Msg = WM_ACQUIRED then begin
- DoAcquired;
- Result := 0;
- end
- else if Msg = WM_RELEASED then begin
- DoReleased;
- Result := 0;
- end
- else
- Result := DefWindowProc(FHandle,Msg,wParam,lParam);
- end; //with
- end; { TGpFileMutexMonitor.WndProc }
-
- { TGpFileGroupMonitor }
-
- {:Creates group monitor component.
- @param AOwner Component owner.
- }
- constructor TGpFileGroupMonitor.Create(AOwner: TComponent);
- begin
- inherited;
- FInterval := 5000;
- FShortDelay := CShortDelay;
- FHandle := AllocateHWnd(WndProc);
- end; { TGpFileGroupMonitor.Create }
-
- {:Destroys group monitor component.
- }
- destructor TGpFileGroupMonitor.Destroy;
- begin
- StopMonitorThread;
- DeallocateHWnd(FHandle);
- FreeAndNil(FFileGroup);
- inherited;
- end; { TGpFileGroupMonitor.Destroy }
-
- {:Called when group becomes empty. Sets internal flag and triggers OnEmpty
- event.
- }
- procedure TGpFileGroupMonitor.DoEmpty;
- begin
- FEmpty := true;
- if assigned(FOnEmpty) then
- FOnEmpty(self);
- end; { TGpFileGroupMonitor.DoEmpty }
-
- {:Called when group becomes nonempty. Sets internal flag and triggers OnNotEmpty
- event.
- }
- procedure TGpFileGroupMonitor.DoNotEmpty;
- begin
- FEmpty := false;
- if assigned(FOnNotEmpty) then
- FOnNotEmpty(self);
- end; { TGpFileGroupMonitor.DoNotEmpty }
-
- function TGpFileGroupMonitor.IsMember: boolean;
- begin
- Result := assigned(FFileGroup);
- end; { TGpFileGroupMonitor.IsMember }
-
- {:Overloaded Join, does not return status.
- @param timeout Timeout in milliseconds. 0 and INFINITE are supported.
- @returns false on timeout.
- @raises EGpFileSync if sync file cannot be created or if already joined.
- }
- function TGpFileGroupMonitor.Join(timeout: DWORD): boolean;
- var
- isFirst: boolean;
- begin
- Result := Join(timeout,isFirst);
- end; { TGpFileGroupMonitor.Join }
-
- {:Joins the group.
- @param timeout Timeout in milliseconds. 0 and INFINITE are supported.
- @param isFirstMember (out) Set to true if this was first member of the
- group. Defined only if function returns true.
- @returns false on timeout.
- @raises EGpFileSync if sync file cannot be created or if already joined.
- }
- function TGpFileGroupMonitor.Join(timeout: DWORD;
- var isFirstMember: boolean): boolean;
- begin
- if IsMember then
- raise EGpFileSync.CreateFmt(SAlreadyJoined,[FGroupFile])
- else begin
- FFileGroup := TGpFileGroup.Create(FGroupFile,FDeleteOnRelease);
- Result := FFileGroup.Join(timeout,isFirstMember);
- if not Result then
- FreeAndNil(FFileGroup)
- else if isFirstMember then
- DoNotEmpty;
- end;
- end; { TGpFileGroupMonitor.Join }
-
- {:Leaves the group.
- @param timeout Timeout in milliseconds. 0 and INFINITE are supported.
- @param wasLastMember (out) Set to true if this was last process in the
- group. Defined only if function returns true.
- @returns false on timeout.
- @raises EGpFileSync if sync file cannot be deleted and this was last member
- and deleteOnRelease was required. Also raised if not joined.
- }
- function TGpFileGroupMonitor.Leave(timeout: DWORD;
- var wasLastMember: boolean): boolean;
- begin
- if not IsMember then
- raise EGpFileSync.CreateFmt(SNotJoined,[FGroupFile])
- else begin
- Result := FFileGroup.Leave(timeout,wasLastMember);
- if Result then begin
- FreeAndNil(FFileGroup);
- if wasLastMember then
- DoEmpty;
- end;
- end;
- end; { TGpFileGroupMonitor.Leave }
-
- {:Overloaded Leave, does not return status.
- @param timeout Timeout in milliseconds. 0 and INFINITE are supported.
- @returns false on timeout.
- @raises EGpFileSync if sync file cannot be deleted and this was last member
- and deleteOnRelease was required. Also raised if not joined.
- }
- function TGpFileGroupMonitor.Leave(timeout: DWORD): boolean;
- var
- wasLast: boolean;
- begin
- Result := Leave(timeout,wasLast);
- end; { TGpFileGroupMonitor.Leave }
-
- procedure TGpFileGroupMonitor.Loaded;
- begin
- inherited;
- if FStreamedActive then
- Active := true;
- end; { TGpFileGroupMonitor.Loaded }
-
- {:Sets Active property. If called during component loading, stores new value to
- be set later when component is fully loaded. Otherwise, starts or stops
- monitoring thread if required.
- @param Value New value of Active property.
- }
- procedure TGpFileGroupMonitor.SetActive(const Value: boolean);
- begin
- if (csReading in ComponentState) then
- FStreamedActive := Value
- else begin
- if FActive <> Value then begin
- FActive := Value;
- if FActive then
- StartMonitorThread(true)
- else
- StopMonitorThread;
- end;
- end;
- end; { TGpFileGroupMonitor.SetActive }
-
- {:Starts monitor thread (if not already started).
- }
- procedure TGpFileGroupMonitor.StartMonitorThread(reportFirst: boolean);
- begin
- if not assigned(FMonitorThread) then begin
- FMonitorThread := TGpFileGroupMonitorThread.Create(FHandle,FInterval,
- FGroupFile,FDeleteOnRelease,FShortDelay,reportFirst);
- end;
- end; { TGpFileGroupMonitor.StartMonitorThread }
-
- {:Stops monitor thread (if not already stopped).
- }
- procedure TGpFileGroupMonitor.StopMonitorThread;
- begin
- if assigned(FMonitorThread) then begin
- TGpFileGroupMonitorThread(FMonitorThread).Terminate;
- FMonitorThread.WaitFor;
- FreeAndNil(FMonitorThread);
- end;
- end; { TGpFileGroupMonitor.StopMonitorThread }
-
- {:Windows message handler. Catches WM_EMPTY and WM_NOTEMPTY user messages and
- converts them into events.
- }
- procedure TGpFileGroupMonitor.WndProc(var MsgRec: TMessage);
- begin
- with MsgRec do begin
- if Msg = WM_EMPTY then begin
- DoEmpty;
- Result := 0;
- end
- else if Msg = WM_NOTEMPTY then begin
- DoNotEmpty;
- Result := 0;
- end
- else
- Result := DefWindowProc(FHandle,Msg,wParam,lParam);
- end; //with
- end; { TGpFileGroupMonitor.WndProc }
-
- { TGpFileGroupMonitorThread }
-
- {:Group monitor thread constructor.
- }
- constructor TGpFileGroupMonitorThread.Create(parentWin: HWND;
- checkInterval: integer; groupFile: string; deleteOnRelease: boolean;
- shortDelay: integer; reportFirst: boolean);
- begin
- FParentWin := parentWin;
- FCheckInterval := checkInterval;
- FShortDelay := shortDelay;
- FReportFirst := reportFirst;
- FFileGroup := TGpFileGroup.Create(groupFile,deleteOnRelease);
- inherited Create(false);
- end; { TGpFileGroupMonitorThread.Create }
-
- {:Group monitor thread destructor.
- }
- destructor TGpFileGroupMonitorThread.Destroy;
- begin
- //safety precaution - that way code will work correctly if caller forgets to Terminate this thread
- Terminate;
- WaitFor;
- //>
- FreeAndNil(FFileGroup);
- inherited;
- end; { TGpFileGroupMonitorThread.Destroy }
-
- {:Group monitor thread main execute loop. Monitors for group changes and reports
- them to the owner.
- }
- procedure TGpFileGroupMonitorThread.SafeExecute;
- var
- newIsEmpty: boolean;
- oldIsEmpty: boolean;
- begin
- if not FFileGroup.IsEmpty(FShortDelay,oldIsEmpty) then
- oldIsEmpty := false;
- if FReportFirst then
- TriggerStatusChange(oldIsEmpty);
- while WaitForSingleObject(TerminateEvent,FCheckInterval) = WAIT_TIMEOUT do begin
- if not FFileGroup.IsEmpty(FShortDelay,newIsEmpty) then
- newIsEmpty := oldIsEmpty;
- if newIsEmpty <> oldIsEmpty then begin
- TriggerStatusChange(newIsEmpty);
- oldIsEmpty := newIsEmpty;
- end;
- end; //while
- end; { TGpFileGroupMonitorThread. }
-
- {:Report mutex status change to the owner by posting an user message.
- }
- procedure TGpFileGroupMonitorThread.TriggerStatusChange(isEmpty: boolean);
- begin
- if isEmpty then
- PostMessage(FParentWin,WM_EMPTY,0,0)
- else
- PostMessage(FParentWin,WM_NOTEMPTY,0,0);
- end; { TGpFileGroupMonitorThread.TriggerStatusChange }
-
- end.
-
-